/**
  ******************************************************************************
  * @file    bsp_power.c
  * @author  Iron
  * @date    2018-07-09
  * @version v1.0
  * @brief   bsp_power c file
  */

/** @addtogroup GROUP_BSP
  * @{
  */

/* includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "bsp.h"
#include "bsp_adc.h"
#include "bsp_power.h"

/* BEBUG LOG */
#include "debug_log.h"
#define LOG_LOCAL_LEVEL DBG_LOG_DEBUG
DBG_LOG_TAG("POWER");

#ifdef LOG_DEBUG_ENABLE
static const char *power_name[] =
{
    "BAT",
    "GPS",
    "GPRS",
    "Sensor"
};
#endif

/* private typedef -----------------------------------------------------------*/
/* private macro -------------------------------------------------------------*/

// Battery Power pin
#define BAT_POWER_PIN         GPIO_PIN_9
#define BAT_POWER_PORT        GPIOB
#define BAT_POWER_ON()        HAL_GPIO_WritePin(BAT_POWER_PORT, BAT_POWER_PIN, GPIO_PIN_SET)
#define BAT_POWER_OFF()       HAL_GPIO_WritePin(BAT_POWER_PORT, BAT_POWER_PIN, GPIO_PIN_RESET)

#define BAT_CHGOK_PIN         GPIO_PIN_4
#define BAT_CHGOK_PORT        GPIOE
#define BAT_CHGOK_STATE()     HAL_GPIO_ReadPin(BAT_CHGOK_PORT, BAT_CHGOK_PIN)

// GPS Power pin
#define GPS_POWER_PIN         GPIO_PIN_3
#define GPS_POWER_PORT        GPIOE
#define GPS_POWER_ON()        HAL_GPIO_WritePin(GPS_POWER_PORT, GPS_POWER_PIN, GPIO_PIN_RESET)
#define GPS_POWER_OFF()       HAL_GPIO_WritePin(GPS_POWER_PORT, GPS_POWER_PIN, GPIO_PIN_SET)

// GPRS Power pin
#define GPRS_POWER_PIN        GPIO_PIN_5
#define GPRS_POWER_PORT       GPIOC
#define GPRS_POWER_ON()       HAL_GPIO_WritePin(GPRS_POWER_PORT, GPRS_POWER_PIN, GPIO_PIN_SET)
#define GPRS_POWER_OFF()      HAL_GPIO_WritePin(GPRS_POWER_PORT, GPRS_POWER_PIN, GPIO_PIN_RESET)

// SENSOR Power pin
#define SENSOR_POWER_PIN      GPIO_PIN_2
#define SENSOR_POWER_PORT     GPIOE
#define SENSOR_POWER_ON()     HAL_GPIO_WritePin(SENSOR_POWER_PORT, SENSOR_POWER_PIN, GPIO_PIN_SET)
#define SENSOR_POWER_OFF()    HAL_GPIO_WritePin(SENSOR_POWER_PORT, SENSOR_POWER_PIN, GPIO_PIN_RESET)

// RCC Config
#define BSP_PWOER_PORT_RCC_INIT() \
    __HAL_RCC_GPIOB_CLK_ENABLE();   \
    __HAL_RCC_GPIOC_CLK_ENABLE();   \
    __HAL_RCC_GPIOE_CLK_ENABLE()

/* private variables ---------------------------------------------------------*/
/* private function prototypes -----------------------------------------------*/
/* private functions ---------------------------------------------------------*/

void bsp_power_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    BSP_PWOER_PORT_RCC_INIT();

    // Battery Power pin
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pin = BAT_POWER_PIN;
    HAL_GPIO_Init(BAT_POWER_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pin = BAT_CHGOK_PIN;
    HAL_GPIO_Init(BAT_CHGOK_PORT, &GPIO_InitStruct);

    // GPS Power pin
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pin  = GPS_POWER_PIN;
    HAL_GPIO_Init(GPS_POWER_PORT, &GPIO_InitStruct);

    // GPRS Power pin
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pin = GPRS_POWER_PIN;
    HAL_GPIO_Init(GPRS_POWER_PORT, &GPIO_InitStruct);

    // SENSOR Power Pin
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pin = SENSOR_POWER_PIN;
    HAL_GPIO_Init(SENSOR_POWER_PORT, &GPIO_InitStruct);

    // default power state
    BAT_POWER_ON();
    GPS_POWER_OFF();
    GPRS_POWER_OFF();
    SENSOR_POWER_OFF();
}

void bsp_power_set(int32_t port, int32_t state)
{
    DBG_LOGD(TAG, "%s power %s", power_name[port], state ? "on" : "off");

    switch (port)
    {
    case bsp_power_bat:
        if (state == BSP_POWER_ON)
        {
            BAT_POWER_ON();
        }
        else
        {
            BAT_POWER_OFF();
        }
        break;

    case bsp_power_gps:
        if (state == BSP_POWER_ON)
        {
            GPS_POWER_ON();
        }
        else
        {
            GPS_POWER_OFF();
        }
        break;

    case bsp_power_gprs:
        if (state == BSP_POWER_ON)
        {
            GPRS_POWER_ON();
        }
        else
        {
            GPRS_POWER_OFF();
        }
        break;

    case bsp_power_sensor:
        if (state == BSP_POWER_ON)
        {
            SENSOR_POWER_ON();
        }
        else
        {
            SENSOR_POWER_OFF();
        }
        break;
    }
}

int32_t bsp_power_bat_charge_state(void)
{
    return BAT_CHGOK_STATE();
}

int32_t bsp_power_check(void)
{
    static uint32_t power_check_tms = 0;
    static uint32_t power_ready_to_shutdown_tms = 0;
    uint32_t voltage, tms;

    voltage = bsp_adc_get_power_car_bat_voltage();   // 外部电源电压

    if (voltage > BSP_BAT_POWER_VOLTAGE && power_check_tms != 0)
    {
        power_check_tms = 0;
        power_ready_to_shutdown_tms = 0;
        DBG_LOGI(TAG, "Device power supply normal. (voltage = %d mV)",  voltage);
    }
    else if (voltage < BSP_BAT_POWER_VOLTAGE)
    {
        if (power_check_tms == 0)
        {
            power_check_tms = bsp_get_time_ms();
            power_ready_to_shutdown_tms = 0;
        }
        else
        {
            tms = bsp_get_time_ms() - power_check_tms;
            if (tms > BSP_BAT_POWER_SHUTDOWM_DELAY_MS)
            {
                DBG_LOGE(TAG, "Device power shutdowm now.");
                bsp_os_delay(100);
                bsp_power_set(bsp_power_bat, BSP_POWER_OFF); // POWER OFF !!
                /* SHUTDWON */
            }
            else if (tms > 1000 && tms < 1200)
            {
                DBG_LOGW(TAG, "Device power supply too low, Device will shutdowm after %ds.", BSP_BAT_POWER_SHUTDOWM_DELAY_MS / 1000);
            }
            else if (tms > (BSP_BAT_POWER_SHUTDOWM_DELAY_MS - 11000))     // last 10s prompt
            {
                if (power_ready_to_shutdown_tms == 0 || (tms - power_ready_to_shutdown_tms > 1000))
                {
                    power_ready_to_shutdown_tms = tms;
                    DBG_LOGW(TAG, "Device power will shutdowm after %ds.", (BSP_BAT_POWER_SHUTDOWM_DELAY_MS - tms) / 1000);
                }
            }
        }
    }

    return 0;
}

/**
  * @}
  */

/******************* (C)COPYRIGHT 2018 ***** END OF FILE *********************/
